home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / cmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  15.9 KB  |  893 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // cmd.c -- Quake script command processing module
  21.  
  22. #include "qcommon.h"
  23.  
  24. void Cmd_ForwardToServer (void);
  25.  
  26. #define    MAX_ALIAS_NAME    32
  27.  
  28. typedef struct cmdalias_s
  29. {
  30.     struct cmdalias_s    *next;
  31.     char    name[MAX_ALIAS_NAME];
  32.     char    *value;
  33. } cmdalias_t;
  34.  
  35. cmdalias_t    *cmd_alias;
  36.  
  37. qboolean    cmd_wait;
  38.  
  39. #define    ALIAS_LOOP_COUNT    16
  40. int        alias_count;        // for detecting runaway loops
  41.  
  42.  
  43. //=============================================================================
  44.  
  45. /*
  46. ============
  47. Cmd_Wait_f
  48.  
  49. Causes execution of the remainder of the command buffer to be delayed until
  50. next frame.  This allows commands like:
  51. bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
  52. ============
  53. */
  54. void Cmd_Wait_f (void)
  55. {
  56.     cmd_wait = true;
  57. }
  58.  
  59.  
  60. /*
  61. =============================================================================
  62.  
  63.                         COMMAND BUFFER
  64.  
  65. =============================================================================
  66. */
  67.  
  68. sizebuf_t    cmd_text;
  69. byte        cmd_text_buf[8192];
  70.  
  71. byte        defer_text_buf[8192];
  72.  
  73. /*
  74. ============
  75. Cbuf_Init
  76. ============
  77. */
  78. void Cbuf_Init (void)
  79. {
  80.     SZ_Init (&cmd_text, cmd_text_buf, sizeof(cmd_text_buf));
  81. }
  82.  
  83. /*
  84. ============
  85. Cbuf_AddText
  86.  
  87. Adds command text at the end of the buffer
  88. ============
  89. */
  90. void Cbuf_AddText (char *text)
  91. {
  92.     int        l;
  93.     
  94.     l = strlen (text);
  95.  
  96.     if (cmd_text.cursize + l >= cmd_text.maxsize)
  97.     {
  98.         Com_Printf ("Cbuf_AddText: overflow\n");
  99.         return;
  100.     }
  101.     SZ_Write (&cmd_text, text, strlen (text));
  102. }
  103.  
  104.  
  105. /*
  106. ============
  107. Cbuf_InsertText
  108.  
  109. Adds command text immediately after the current command
  110. Adds a \n to the text
  111. FIXME: actually change the command buffer to do less copying
  112. ============
  113. */
  114. void Cbuf_InsertText (char *text)
  115. {
  116.     char    *temp;
  117.     int        templen;
  118.  
  119. // copy off any commands still remaining in the exec buffer
  120.     templen = cmd_text.cursize;
  121.     if (templen)
  122.     {
  123.         temp = Z_Malloc (templen);
  124.         memcpy (temp, cmd_text.data, templen);
  125.         SZ_Clear (&cmd_text);
  126.     }
  127.     else
  128.         temp = NULL;    // shut up compiler
  129.         
  130. // add the entire text of the file
  131.     Cbuf_AddText (text);
  132.     
  133. // add the copied off data
  134.     if (templen)
  135.     {
  136.         SZ_Write (&cmd_text, temp, templen);
  137.         Z_Free (temp);
  138.     }
  139. }
  140.  
  141.  
  142. /*
  143. ============
  144. Cbuf_CopyToDefer
  145. ============
  146. */
  147. void Cbuf_CopyToDefer (void)
  148. {
  149.     memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
  150.     defer_text_buf[cmd_text.cursize] = 0;
  151.     cmd_text.cursize = 0;
  152. }
  153.  
  154. /*
  155. ============
  156. Cbuf_InsertFromDefer
  157. ============
  158. */
  159. void Cbuf_InsertFromDefer (void)
  160. {
  161.     Cbuf_InsertText (defer_text_buf);
  162.     defer_text_buf[0] = 0;
  163. }
  164.  
  165.  
  166. /*
  167. ============
  168. Cbuf_ExecuteText
  169. ============
  170. */
  171. void Cbuf_ExecuteText (int exec_when, char *text)
  172. {
  173.     switch (exec_when)
  174.     {
  175.     case EXEC_NOW:
  176.         Cmd_ExecuteString (text);
  177.         break;
  178.     case EXEC_INSERT:
  179.         Cbuf_InsertText (text);
  180.         break;
  181.     case EXEC_APPEND:
  182.         Cbuf_AddText (text);
  183.         break;
  184.     default:
  185.         Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
  186.     }
  187. }
  188.  
  189. /*
  190. ============
  191. Cbuf_Execute
  192. ============
  193. */
  194. void Cbuf_Execute (void)
  195. {
  196.     int        i;
  197.     char    *text;
  198.     char    line[1024];
  199.     int        quotes;
  200.  
  201.     alias_count = 0;        // don't allow infinite alias loops
  202.  
  203.     while (cmd_text.cursize)
  204.     {
  205. // find a \n or ; line break
  206.         text = (char *)cmd_text.data;
  207.  
  208.         quotes = 0;
  209.         for (i=0 ; i< cmd_text.cursize ; i++)
  210.         {
  211.             if (text[i] == '"')
  212.                 quotes++;
  213.             if ( !(quotes&1) &&  text[i] == ';')
  214.                 break;    // don't break if inside a quoted string
  215.             if (text[i] == '\n')
  216.                 break;
  217.         }
  218.             
  219.                 
  220.         memcpy (line, text, i);
  221.         line[i] = 0;
  222.         
  223. // delete the text from the command buffer and move remaining commands down
  224. // this is necessary because commands (exec, alias) can insert data at the
  225. // beginning of the text buffer
  226.  
  227.         if (i == cmd_text.cursize)
  228.             cmd_text.cursize = 0;
  229.         else
  230.         {
  231.             i++;
  232.             cmd_text.cursize -= i;
  233.             memmove (text, text+i, cmd_text.cursize);
  234.         }
  235.  
  236. // execute the command line
  237.         Cmd_ExecuteString (line);
  238.         
  239.         if (cmd_wait)
  240.         {
  241.             // skip out while text still remains in buffer, leaving it
  242.             // for next frame
  243.             cmd_wait = false;
  244.             break;
  245.         }
  246.     }
  247. }
  248.  
  249.  
  250. /*
  251. ===============
  252. Cbuf_AddEarlyCommands
  253.  
  254. Adds command line parameters as script statements
  255. Commands lead with a +, and continue until another +
  256.  
  257. Set commands are added early, so they are guaranteed to be set before
  258. the client and server initialize for the first time.
  259.  
  260. Other commands are added late, after all initialization is complete.
  261. ===============
  262. */
  263. void Cbuf_AddEarlyCommands (qboolean clear)
  264. {
  265.     int        i;
  266.     char    *s;
  267.  
  268.     for (i=0 ; i<COM_Argc() ; i++)
  269.     {
  270.         s = COM_Argv(i);
  271.         if (strcmp (s, "+set"))
  272.             continue;
  273.         Cbuf_AddText (va("set %s %s\n", COM_Argv(i+1), COM_Argv(i+2)));
  274.         if (clear)
  275.         {
  276.             COM_ClearArgv(i);
  277.             COM_ClearArgv(i+1);
  278.             COM_ClearArgv(i+2);
  279.         }
  280.         i+=2;
  281.     }
  282. }
  283.  
  284. /*
  285. =================
  286. Cbuf_AddLateCommands
  287.  
  288. Adds command line parameters as script statements
  289. Commands lead with a + and continue until another + or -
  290. quake +vid_ref gl +map amlev1
  291.  
  292. Returns true if any late commands were added, which
  293. will keep the demoloop from immediately starting
  294. =================
  295. */
  296. qboolean Cbuf_AddLateCommands (void)
  297. {
  298.     int        i, j;
  299.     int        s;
  300.     char    *text, *build, c;
  301.     int        argc;
  302.     qboolean    ret;
  303.  
  304. // build the combined string to parse from
  305.     s = 0;
  306.     argc = COM_Argc();
  307.     for (i=1 ; i<argc ; i++)
  308.     {
  309.         s += strlen (COM_Argv(i)) + 1;
  310.     }
  311.     if (!s)
  312.         return false;
  313.         
  314.     text = Z_Malloc (s+1);
  315.     text[0] = 0;
  316.     for (i=1 ; i<argc ; i++)
  317.     {
  318.         strcat (text,COM_Argv(i));
  319.         if (i != argc-1)
  320.             strcat (text, " ");
  321.     }
  322.     
  323. // pull out the commands
  324.     build = Z_Malloc (s+1);
  325.     build[0] = 0;
  326.     
  327.     for (i=0 ; i<s-1 ; i++)
  328.     {
  329.         if (text[i] == '+')
  330.         {
  331.             i++;
  332.  
  333.             for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
  334.                 ;
  335.  
  336.             c = text[j];
  337.             text[j] = 0;
  338.             
  339.             strcat (build, text+i);
  340.             strcat (build, "\n");
  341.             text[j] = c;
  342.             i = j-1;
  343.         }
  344.     }
  345.  
  346.     ret = (build[0] != 0);
  347.     if (ret)
  348.         Cbuf_AddText (build);
  349.     
  350.     Z_Free (text);
  351.     Z_Free (build);
  352.  
  353.     return ret;
  354. }
  355.  
  356.  
  357. /*
  358. ==============================================================================
  359.  
  360.                         SCRIPT COMMANDS
  361.  
  362. ==============================================================================
  363. */
  364.  
  365.  
  366. /*
  367. ===============
  368. Cmd_Exec_f
  369. ===============
  370. */
  371. void Cmd_Exec_f (void)
  372. {
  373.     char    *f, *f2;
  374.     int        len;
  375.  
  376.     if (Cmd_Argc () != 2)
  377.     {
  378.         Com_Printf ("exec <filename> : execute a script file\n");
  379.         return;
  380.     }
  381.  
  382.     len = FS_LoadFile (Cmd_Argv(1), (void **)&f);
  383.     if (!f)
  384.     {
  385.         Com_Printf ("couldn't exec %s\n",Cmd_Argv(1));
  386.         return;
  387.     }
  388.     Com_Printf ("execing %s\n",Cmd_Argv(1));
  389.     
  390.     // the file doesn't have a trailing 0, so we need to copy it off
  391.     f2 = Z_Malloc(len+1);
  392.     memcpy (f2, f, len);
  393.     f2[len] = 0;
  394.  
  395.     Cbuf_InsertText (f2);
  396.  
  397.     Z_Free (f2);
  398.     FS_FreeFile (f);
  399. }
  400.  
  401.  
  402. /*
  403. ===============
  404. Cmd_Echo_f
  405.  
  406. Just prints the rest of the line to the console
  407. ===============
  408. */
  409. void Cmd_Echo_f (void)
  410. {
  411.     int        i;
  412.     
  413.     for (i=1 ; i<Cmd_Argc() ; i++)
  414.         Com_Printf ("%s ",Cmd_Argv(i));
  415.     Com_Printf ("\n");
  416. }
  417.  
  418. /*
  419. ===============
  420. Cmd_Alias_f
  421.  
  422. Creates a new command that executes a command string (possibly ; seperated)
  423. ===============
  424. */
  425. void Cmd_Alias_f (void)
  426. {
  427.     cmdalias_t    *a;
  428.     char        cmd[1024];
  429.     int            i, c;
  430.     char        *s;
  431.  
  432.     if (Cmd_Argc() == 1)
  433.     {
  434.         Com_Printf ("Current alias commands:\n");
  435.         for (a = cmd_alias ; a ; a=a->next)
  436.             Com_Printf ("%s : %s\n", a->name, a->value);
  437.         return;
  438.     }
  439.  
  440.     s = Cmd_Argv(1);
  441.     if (strlen(s) >= MAX_ALIAS_NAME)
  442.     {
  443.         Com_Printf ("Alias name is too long\n");
  444.         return;
  445.     }
  446.  
  447.     // if the alias already exists, reuse it
  448.     for (a = cmd_alias ; a ; a=a->next)
  449.     {
  450.         if (!strcmp(s, a->name))
  451.         {
  452.             Z_Free (a->value);
  453.             break;
  454.         }
  455.     }
  456.  
  457.     if (!a)
  458.     {
  459.         a = Z_Malloc (sizeof(cmdalias_t));
  460.         a->next = cmd_alias;
  461.         cmd_alias = a;
  462.     }
  463.     strcpy (a->name, s);    
  464.  
  465. // copy the rest of the command line
  466.     cmd[0] = 0;        // start out with a null string
  467.     c = Cmd_Argc();
  468.     for (i=2 ; i< c ; i++)
  469.     {
  470.         strcat (cmd, Cmd_Argv(i));
  471.         if (i != (c - 1))
  472.             strcat (cmd, " ");
  473.     }
  474.     strcat (cmd, "\n");
  475.     
  476.     a->value = CopyString (cmd);
  477. }
  478.  
  479. /*
  480. =============================================================================
  481.  
  482.                     COMMAND EXECUTION
  483.  
  484. =============================================================================
  485. */
  486.  
  487. typedef struct cmd_function_s
  488. {
  489.     struct cmd_function_s    *next;
  490.     char                    *name;
  491.     xcommand_t                function;
  492. } cmd_function_t;
  493.  
  494.  
  495. static    int            cmd_argc;
  496. static    char        *cmd_argv[MAX_STRING_TOKENS];
  497. static    char        *cmd_null_string = "";
  498. static    char        cmd_args[MAX_STRING_CHARS];
  499.  
  500. static    cmd_function_t    *cmd_functions;        // possible commands to execute
  501.  
  502. /*
  503. ============
  504. Cmd_Argc
  505. ============
  506. */
  507. int        Cmd_Argc (void)
  508. {
  509.     return cmd_argc;
  510. }
  511.  
  512. /*
  513. ============
  514. Cmd_Argv
  515. ============
  516. */
  517. char    *Cmd_Argv (int arg)
  518. {
  519.     if ( (unsigned)arg >= cmd_argc )
  520.         return cmd_null_string;
  521.     return cmd_argv[arg];    
  522. }
  523.  
  524. /*
  525. ============
  526. Cmd_Args
  527.  
  528. Returns a single string containing argv(1) to argv(argc()-1)
  529. ============
  530. */
  531. char        *Cmd_Args (void)
  532. {
  533.     return cmd_args;
  534. }
  535.  
  536.  
  537. /*
  538. ======================
  539. Cmd_MacroExpandString
  540. ======================
  541. */
  542. char *Cmd_MacroExpandString (char *text)
  543. {
  544.     int        i, j, count, len;
  545.     qboolean    inquote;
  546.     char    *scan;
  547.     static    char    expanded[MAX_STRING_CHARS];
  548.     char    temporary[MAX_STRING_CHARS];
  549.     char    *token, *start;
  550.  
  551.     inquote = false;
  552.     scan = text;
  553.  
  554.     len = strlen (scan);
  555.     if (len >= MAX_STRING_CHARS)
  556.     {
  557.         Com_Printf ("Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
  558.         return NULL;
  559.     }
  560.  
  561.     count = 0;
  562.  
  563.     for (i=0 ; i<len ; i++)
  564.     {
  565.         if (scan[i] == '"')
  566.             inquote ^= 1;
  567.         if (inquote)
  568.             continue;    // don't expand inside quotes
  569.         if (scan[i] != '$')
  570.             continue;
  571.         // scan out the complete macro
  572.         start = scan+i+1;
  573.         token = COM_Parse (&start);
  574.         if (!start)
  575.             continue;
  576.     
  577.         token = Cvar_VariableString (token);
  578.  
  579.         j = strlen(token);
  580.         len += j;
  581.         if (len >= MAX_STRING_CHARS)
  582.         {
  583.             Com_Printf ("Expanded line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
  584.             return NULL;
  585.         }
  586.  
  587.         strncpy (temporary, scan, i);
  588.         strcpy (temporary+i, token);
  589.         strcpy (temporary+i+j, start);
  590.  
  591.         strcpy (expanded, temporary);
  592.         scan = expanded;
  593.         i--;
  594.  
  595.         if (++count == 100)
  596.         {
  597.             Com_Printf ("Macro expansion loop, discarded.\n");
  598.             return NULL;
  599.         }
  600.     }
  601.  
  602.     if (inquote)
  603.     {
  604.         Com_Printf ("Line has unmatched quote, discarded.\n");
  605.         return NULL;
  606.     }
  607.  
  608.     return scan;
  609. }
  610.  
  611.  
  612. /*
  613. ============
  614. Cmd_TokenizeString
  615.  
  616. Parses the given string into command line tokens.
  617. $Cvars will be expanded unless they are in a quoted token
  618. ============
  619. */
  620. void Cmd_TokenizeString (char *text, qboolean macroExpand)
  621. {
  622.     int        i;
  623.     char    *com_token;
  624.  
  625. // clear the args from the last string
  626.     for (i=0 ; i<cmd_argc ; i++)
  627.         Z_Free (cmd_argv[i]);
  628.         
  629.     cmd_argc = 0;
  630.     cmd_args[0] = 0;
  631.     
  632.     // macro expand the text
  633.     if (macroExpand)
  634.         text = Cmd_MacroExpandString (text);
  635.     if (!text)
  636.         return;
  637.  
  638.     while (1)
  639.     {
  640. // skip whitespace up to a /n
  641.         while (*text && *text <= ' ' && *text != '\n')
  642.         {
  643.             text++;
  644.         }
  645.         
  646.         if (*text == '\n')
  647.         {    // a newline seperates commands in the buffer
  648.             text++;
  649.             break;
  650.         }
  651.  
  652.         if (!*text)
  653.             return;
  654.  
  655.         // set cmd_args to everything after the first arg
  656.         if (cmd_argc == 1)
  657.         {
  658.             int        l;
  659.  
  660.             strcpy (cmd_args, text);
  661.  
  662.             // strip off any trailing whitespace
  663.             l = strlen(cmd_args) - 1;
  664.             for ( ; l >= 0 ; l--)
  665.                 if (cmd_args[l] <= ' ')
  666.                     cmd_args[l] = 0;
  667.                 else
  668.                     break;
  669.         }
  670.             
  671.         com_token = COM_Parse (&text);
  672.         if (!text)
  673.             return;
  674.  
  675.         if (cmd_argc < MAX_STRING_TOKENS)
  676.         {
  677.             cmd_argv[cmd_argc] = Z_Malloc (strlen(com_token)+1);
  678.             strcpy (cmd_argv[cmd_argc], com_token);
  679.             cmd_argc++;
  680.         }
  681.     }
  682.     
  683. }
  684.  
  685.  
  686. /*
  687. ============
  688. Cmd_AddCommand
  689. ============
  690. */
  691. void    Cmd_AddCommand (char *cmd_name, xcommand_t function)
  692. {
  693.     cmd_function_t    *cmd;
  694.     
  695. // fail if the command is a variable name
  696.     if (Cvar_VariableString(cmd_name)[0])
  697.     {
  698.         Com_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
  699.         return;
  700.     }
  701.     
  702. // fail if the command already exists
  703.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  704.     {
  705.         if (!strcmp (cmd_name, cmd->name))
  706.         {
  707.             Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
  708.             return;
  709.         }
  710.     }
  711.  
  712.     cmd = Z_Malloc (sizeof(cmd_function_t));
  713.     cmd->name = cmd_name;
  714.     cmd->function = function;
  715.     cmd->next = cmd_functions;
  716.     cmd_functions = cmd;
  717. }
  718.  
  719. /*
  720. ============
  721. Cmd_RemoveCommand
  722. ============
  723. */
  724. void    Cmd_RemoveCommand (char *cmd_name)
  725. {
  726.     cmd_function_t    *cmd, **back;
  727.  
  728.     back = &cmd_functions;
  729.     while (1)
  730.     {
  731.         cmd = *back;
  732.         if (!cmd)
  733.         {
  734.             Com_Printf ("Cmd_RemoveCommand: %s not added\n", cmd_name);
  735.             return;
  736.         }
  737.         if (!strcmp (cmd_name, cmd->name))
  738.         {
  739.             *back = cmd->next;
  740.             Z_Free (cmd);
  741.             return;
  742.         }
  743.         back = &cmd->next;
  744.     }
  745. }
  746.  
  747. /*
  748. ============
  749. Cmd_Exists
  750. ============
  751. */
  752. qboolean    Cmd_Exists (char *cmd_name)
  753. {
  754.     cmd_function_t    *cmd;
  755.  
  756.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  757.     {
  758.         if (!strcmp (cmd_name,cmd->name))
  759.             return true;
  760.     }
  761.  
  762.     return false;
  763. }
  764.  
  765.  
  766.  
  767. /*
  768. ============
  769. Cmd_CompleteCommand
  770. ============
  771. */
  772. char *Cmd_CompleteCommand (char *partial)
  773. {
  774.     cmd_function_t    *cmd;
  775.     int                len;
  776.     cmdalias_t        *a;
  777.     
  778.     len = strlen(partial);
  779.     
  780.     if (!len)
  781.         return NULL;
  782.         
  783. // check for exact match
  784.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  785.         if (!strcmp (partial,cmd->name))
  786.             return cmd->name;
  787.     for (a=cmd_alias ; a ; a=a->next)
  788.         if (!strcmp (partial, a->name))
  789.             return a->name;
  790.  
  791. // check for partial match
  792.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  793.         if (!strncmp (partial,cmd->name, len))
  794.             return cmd->name;
  795.     for (a=cmd_alias ; a ; a=a->next)
  796.         if (!strncmp (partial, a->name, len))
  797.             return a->name;
  798.  
  799.     return NULL;
  800. }
  801.  
  802.  
  803. /*
  804. ============
  805. Cmd_ExecuteString
  806.  
  807. A complete command line has been parsed, so try to execute it
  808. FIXME: lookupnoadd the token to speed search?
  809. ============
  810. */
  811. void    Cmd_ExecuteString (char *text)
  812. {    
  813.     cmd_function_t    *cmd;
  814.     cmdalias_t        *a;
  815.  
  816.     Cmd_TokenizeString (text, true);
  817.             
  818.     // execute the command line
  819.     if (!Cmd_Argc())
  820.         return;        // no tokens
  821.  
  822.     // check functions
  823.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  824.     {
  825.         if (!Q_strcasecmp (cmd_argv[0],cmd->name))
  826.         {
  827.             if (!cmd->function)
  828.             {    // forward to server command
  829.                 Cmd_ExecuteString (va("cmd %s", text));
  830.             }
  831.             else
  832.                 cmd->function ();
  833.             return;
  834.         }
  835.     }
  836.  
  837.     // check alias
  838.     for (a=cmd_alias ; a ; a=a->next)
  839.     {
  840.         if (!Q_strcasecmp (cmd_argv[0], a->name))
  841.         {
  842.             if (++alias_count == ALIAS_LOOP_COUNT)
  843.             {
  844.                 Com_Printf ("ALIAS_LOOP_COUNT\n");
  845.                 return;
  846.             }
  847.             Cbuf_InsertText (a->value);
  848.             return;
  849.         }
  850.     }
  851.     
  852.     // check cvars
  853.     if (Cvar_Command ())
  854.         return;
  855.  
  856.     // send it as a server command if we are connected
  857.     Cmd_ForwardToServer ();
  858. }
  859.  
  860. /*
  861. ============
  862. Cmd_List_f
  863. ============
  864. */
  865. void Cmd_List_f (void)
  866. {
  867.     cmd_function_t    *cmd;
  868.     int                i;
  869.  
  870.     i = 0;
  871.     for (cmd=cmd_functions ; cmd ; cmd=cmd->next, i++)
  872.         Com_Printf ("%s\n", cmd->name);
  873.     Com_Printf ("%i commands\n", i);
  874. }
  875.  
  876. /*
  877. ============
  878. Cmd_Init
  879. ============
  880. */
  881. void Cmd_Init (void)
  882. {
  883. //
  884. // register our commands
  885. //
  886.     Cmd_AddCommand ("cmdlist",Cmd_List_f);
  887.     Cmd_AddCommand ("exec",Cmd_Exec_f);
  888.     Cmd_AddCommand ("echo",Cmd_Echo_f);
  889.     Cmd_AddCommand ("alias",Cmd_Alias_f);
  890.     Cmd_AddCommand ("wait", Cmd_Wait_f);
  891. }
  892.  
  893.